"""
function:读取Excel不同sheet（可手动选择）的上报区划获取文件路径（映射），然后树状遍历路径下的文件夹，根据Excel文件中的报表名称模糊匹配文件（'.xls','.xlsx','.doc','.docx','.pdf','.csv'），根据序号重命名文件并复制到另外的路径。
author:wenzhengxing
date:2025/08/20 17:18
version:final
"""

import os
import re
import shutil
import pandas as pd
from tkinter import Tk, filedialog, messagebox, simpledialog, Listbox, MULTIPLE, END, Button, Label, Frame, Text, \
    Scrollbar
from fuzzywuzzy import fuzz  # 需要安装：pip install fuzzywuzzy python-Levenshtein

"""
模糊匹配逻辑
1、序号匹配阶段：首先收集所有包含原表序号的文件
2、判断：在序号匹配的文件中，如果文件名有汉字，使用汉字匹配进一步筛选，找到最佳匹配，如果文件名没有汉字则默认匹配上
3、全局匹配阶段：无论是否有序号匹配，都会进行全局的纯汉字匹配
4、最终决策：比较序号匹配和全局匹配的结果，选择分数更高的匹配
5、最后：如果找不到完全匹配的数字文件名，则寻找包含序号的文件名

如果序号匹配且汉字匹配度高，优先使用序号匹配结果
如果序号匹配但汉字匹配度不够高，会继续全局匹配寻找更好的匹配
如果没有序号匹配，直接使用全局匹配结果
最终没有匹配到的报表名称，用原表序号匹配只有序号的文件名
"""

# 支持的扩展名列表
VALID_EXTENSIONS = ['.xls', '.xlsx', '.doc', '.docx', '.pdf', '.csv', '.wps', '.jpg','.et']

# 需要去除的地点标志列表（可根据实际情况扩展）
LOCATION_KEYWORDS = ["年", "年度", "大圩镇", "合肥市", "街道", "宣城市", "宣州区", "宁国市", "包河区", "埇桥区","朱桥乡", "砀山县", "宿州市", "芜湖路",
                     "镇西村", "韩池孜社区", "砀城镇", "朱仙庄镇", "沈福村", "沱河街道", "周寨镇", "安徽省", "长丰县",
                     "镇园区", "（", "）", "甲路镇","吴山镇", "庄墓镇", "2025", "2024", "统计表", "汇总表", "登记总表", "评分表", "登记",
                     "台账", "表", "申报表", "清单","清册表", "申请表", "进度表", "自查表", "记录表", "花名册", "审核确认表", "（第一期）", "（第一批）",
                     "问题清单", "（工业）（建筑业）（房地产业）（服务业商贸业）", "（街镇）", "（区级）", "（不含迁坟）","居委会疫苗","附件"]


def select_excel_file():
    """选择Excel文件并返回路径"""
    root = Tk()
    root.withdraw()
    file_path = filedialog.askopenfilename(
        title="选择Excel文件",
        filetypes=[("Excel文件", "*.xls *.xlsx")]
    )
    root.destroy()
    return file_path


def get_sheets(excel_path):
    """获取Excel中的所有sheet名称"""
    return pd.ExcelFile(excel_path).sheet_names


def select_sheets(sheets, exclude=None):
    """让用户选择要处理的sheet，排除指定的sheet"""
    if exclude is None:
        exclude = []

    root = Tk()
    root.title("选择Sheet")

    Label(root, text="请选择要处理的sheet（可多选）:").pack(padx=10, pady=5)
    listbox = Listbox(root, selectmode=MULTIPLE, width=50, height=15)
    for sheet in sheets:
        if sheet not in exclude:
            listbox.insert(END, sheet)
    listbox.pack(padx=10, pady=5)

    selected_sheets = []

    def on_confirm():
        nonlocal selected_sheets
        selected_sheets = [listbox.get(i) for i in listbox.curselection()]
        root.destroy()

    Button(root, text="确认", command=on_confirm).pack(pady=10)
    root.mainloop()
    return selected_sheets


def select_target_folder():
    """选择目标文件夹"""
    root = Tk()
    root.withdraw()
    folder = filedialog.askdirectory(title="选择保存文件的目标文件夹")
    root.destroy()
    return folder


def remove_location_keywords(text):
    """去除文本中的地点关键词"""
    for keyword in LOCATION_KEYWORDS:
        text = text.replace(keyword, "")
    return text


def clean_report_name(text):
    """清理报表名称：去除地点关键词、数字和标点，只保留汉字"""
    # 去除地点关键词
    cleaned = remove_location_keywords(text)
    # 移除非汉字字符（保留汉字）
    cleaned = re.sub(r'[^\u4e00-\u9fff]', '', cleaned)
    return cleaned


def clean_file_name(text):
    """清理文件名：去除数字和标点，只保留汉字"""
    # 移除非汉字字符（保留汉字）
    cleaned = re.sub(r'[^\u4e00-\u9fff]', '', text)
    return cleaned


def calculate_char_match_ratio(report_chars, filename_str):
    """计算字符匹配比例"""
    if not report_chars:
        return 0.0

    # 创建filename字符串的可变字符列表
    filename_chars = list(filename_str)
    matched_count = 0

    for char in report_chars:
        if char in filename_chars:
            matched_count += 1
            # 从列表中移除匹配的字符（避免重复匹配）
            filename_chars.remove(char)

    return matched_count / len(report_chars)


def is_number_only_filename(filename):
    """检查文件名是否只包含数字（可能还有扩展名）"""
    # 移除扩展名
    name_without_ext = os.path.splitext(filename)[0]
    # 检查是否只包含数字
    return name_without_ext.isdigit()


# def find_first_file(source_folder, report_name, serial_number):
#     """在文件夹树中递归查找第一个匹配的文件（优先匹配原表序号，然后使用汉字模糊匹配）"""
#     # 将原表序号转换为字符串（用于匹配）
#     serial_str = str(serial_number).strip() if pd.notna(serial_number) else ""
#
#     # 清理报表名称：去除地点关键词、数字和标点，只保留汉字
#     cleaned_report = clean_report_name(report_name)
#     if not cleaned_report:
#         cleaned_report = report_name
#
#     # 将报表名称拆分为单个汉字
#     report_chars = list(cleaned_report)
#
#     # 第一步：优先匹配原表序号
#     if serial_str:
#         serial_matches = []
#         for root_dir, _, files in os.walk(source_folder):
#             for file in files:
#                 file_name, ext = os.path.splitext(file)
#                 if ext.lower() not in VALID_EXTENSIONS:
#                     continue
#
#                 # 检查文件名是否包含原表序号
#                 if serial_str in file_name:
#                     print(f"序号匹配成功: '{file_name}' (包含序号: {serial_str})")
#                     serial_matches.append(os.path.join(root_dir, file))
#
#         # 如果在序号匹配中找到文件，进一步使用汉字匹配筛选
#         if serial_matches:
#             best_serial_match = None
#             highest_serial_score = 0
#
#             for match in serial_matches:
#                 file_name = os.path.splitext(os.path.basename(match))[0]
#                 cleaned_filename = clean_file_name(file_name)
#
#                 # 计算字符匹配比例
#                 char_match_ratio = calculate_char_match_ratio(report_chars, cleaned_filename)
#
#                 # 使用模糊匹配分数
#                 similarity = fuzz.partial_ratio(cleaned_report, cleaned_filename)
#
#                 # 综合评分（可以调整权重）
#                 total_score = char_match_ratio * 0.7 + similarity / 100 * 0.3
#
#                 print(
#                     f"序号匹配后汉字筛选: '{report_name}' -> '{file_name}', 字符匹配率: {char_match_ratio:.2%}, 模糊匹配: {similarity}%, 总分: {total_score:.2f}")
#
#                 if total_score > highest_serial_score:
#                     highest_serial_score = total_score
#                     best_serial_match = match
#
#             # 如果序号匹配的文件中有汉字匹配度高的，直接返回
#             if highest_serial_score > 0.5:  # 设置一个较高的阈值
#                 print(f"序号+汉字最佳匹配: {best_serial_match} (分数: {highest_serial_score:.2f})")
#                 return best_serial_match
#
#             # 如果序号匹配但汉字匹配度不够高，记录最佳序号匹配，但继续全局汉字匹配
#             print(f"序号匹配但汉字匹配度不足 (分数: {highest_serial_score:.2f})，继续全局匹配")
#
#     # 第二步：全局纯汉字匹配（无论是否有序号匹配）
#     best_global_match = None
#     highest_global_score = 0
#
#     for root_dir, _, files in os.walk(source_folder):
#         for file in files:
#             file_name, ext = os.path.splitext(file)
#             if ext.lower() not in VALID_EXTENSIONS:
#                 continue
#
#             # 清理文件名：去除数字和标点，只保留汉字
#             cleaned_filename = clean_file_name(file_name)
#
#             # 计算字符匹配比例
#             char_match_ratio = calculate_char_match_ratio(report_chars, cleaned_filename)
#
#             # 使用模糊匹配分数
#             similarity = fuzz.partial_ratio(cleaned_report, cleaned_filename)
#
#             # 检查核心词序列是否按顺序出现
#             sequential_match = True
#             last_index = -1
#             for char in cleaned_report:
#                 current_index = cleaned_filename.find(char, last_index + 1)
#                 if current_index == -1:
#                     sequential_match = False
#                     break
#                 last_index = current_index
#
#             # 综合评分
#             total_score = char_match_ratio * 0.7 + similarity / 100 * 0.3
#             if sequential_match:
#                 total_score += 0.2  # 顺序匹配加分
#
#             # 调试信息
#             debug_info = (
#                 f"全局匹配检测: '{report_name}' (序号: {serial_str}) -> '{file_name}'\n"
#                 f"清理后报表: '{cleaned_report}' (字符: {report_chars})\n"
#                 f"清理后文件: '{cleaned_filename}'\n"
#                 f"字符匹配率: {char_match_ratio:.2%}, 模糊匹配: {similarity}%, "
#                 f"顺序匹配: {sequential_match}, 总分: {total_score:.2f}"
#             )
#             print(debug_info)
#
#             # 放宽字符匹配率阈值
#             if char_match_ratio >= 0.8:  # 原为0.95
#                 print(f"字符匹配成功 (匹配率: {char_match_ratio:.2%})")
#                 return os.path.join(root_dir, file)
#
#             # 放宽模糊匹配阈值
#             if similarity >= 75:  # 原为85
#                 print(f"模糊匹配成功 (相似度: {similarity}%)")
#                 return os.path.join(root_dir, file)
#
#             # 更新最佳匹配
#             if total_score > highest_global_score:
#                 highest_global_score = total_score
#                 best_global_match = os.path.join(root_dir, file)
#
#     # 降低全局匹配的阈值
#     if highest_global_score > 0.4:  # 原为0.5
#         print(f"全局最佳匹配: {best_global_match} (分数: {highest_global_score:.2f})")
#         return best_global_match
#
#     # 第三步：如果以上都没有匹配到，且有序号，则匹配只包含序号的文件（忽略汉字）
#     if serial_str:
#         print(f"尝试匹配只包含序号的文件: {serial_str}")
#         for root_dir, _, files in os.walk(source_folder):
#             for file in files:
#                 file_name, ext = os.path.splitext(file)
#                 if ext.lower() not in VALID_EXTENSIONS:
#                     continue
#
#                 # 检查文件名是否只包含数字（可能是序号）
#                 if is_number_only_filename(file_name):
#                     # 检查文件名中的数字是否与序号匹配
#                     file_number = os.path.splitext(file)[0]
#                     if file_number == serial_str:
#                         print(f"找到只包含序号的文件: {file_name} (匹配序号: {serial_str})")
#                         return os.path.join(root_dir, file)
#
#                 # 检查文件名是否包含序号（即使有其他字符）
#                 if serial_str in file_name:
#                     # 进一步检查文件名中是否几乎没有汉字
#                     cleaned_filename = clean_file_name(file_name)
#                     if len(cleaned_filename) <= 2:  # 如果汉字很少，认为是序号文件
#                         print(
#                             f"找到以序号为主的文件: {file_name} (包含序号: {serial_str}, 汉字数量: {len(cleaned_filename)})")
#                         return os.path.join(root_dir, file)
#
#     # 没有找到匹配文件
#     print(f"未匹配: '{report_name}' (序号: {serial_str}, 清理后: '{cleaned_report}')")
#     return None

def find_first_file(source_folder, report_name, serial_number):
    """在文件夹树中递归查找第一个匹配的文件（优先匹配原表序号，然后使用汉字模糊匹配）"""
    # 将原表序号转换为字符串（用于匹配）
    serial_str = str(serial_number).strip() if pd.notna(serial_number) else ""

    # 清理报表名称：去除地点关键词、数字和标点，只保留汉字
    cleaned_report = clean_report_name(report_name)
    if not cleaned_report:
        cleaned_report = report_name

    # 将报表名称拆分为单个汉字
    report_chars = list(cleaned_report)

    # 第一步：优先匹配原表序号
    if serial_str:
        serial_matches = []
        for root_dir, _, files in os.walk(source_folder):
            for file in files:
                file_name, ext = os.path.splitext(file)
                if ext.lower() not in VALID_EXTENSIONS:
                    continue

                # 检查文件名是否包含原表序号
                if serial_str in file_name:
                    print(f"序号匹配成功: '{file_name}' (包含序号: {serial_str})")
                    serial_matches.append((os.path.join(root_dir, file), file_name))

        # 如果在序号匹配中找到文件
        if serial_matches:
            # 检查是否有不包含汉字的文件名（纯数字或主要包含序号）
            non_chinese_matches = []
            chinese_matches = []

            for match, file_name in serial_matches:
                # 检查文件名是否包含汉字
                if contains_chinese(file_name):
                    chinese_matches.append((match, file_name))
                else:
                    non_chinese_matches.append((match, file_name))

            # 优先处理不包含汉字的匹配（直接返回第一个）
            if non_chinese_matches:
                print(f"找到不包含汉字的序号匹配文件: {non_chinese_matches[0][1]}")
                return non_chinese_matches[0][0]

            # 处理包含汉字的匹配（使用汉字匹配筛选）
            if chinese_matches:
                best_serial_match = None
                highest_serial_score = 0

                for match, file_name in chinese_matches:
                    cleaned_filename = clean_file_name(file_name)

                    # 计算字符匹配比例
                    char_match_ratio = calculate_char_match_ratio(report_chars, cleaned_filename)

                    # 使用模糊匹配分数
                    similarity = fuzz.partial_ratio(cleaned_report, cleaned_filename)

                    # 综合评分（可以调整权重）
                    total_score = char_match_ratio * 0.7 + similarity / 100 * 0.3

                    print(
                        f"序号匹配后汉字筛选: '{report_name}' -> '{file_name}', 字符匹配率: {char_match_ratio:.2%}, 模糊匹配: {similarity}%, 总分: {total_score:.2f}")

                    if total_score > highest_serial_score:
                        highest_serial_score = total_score
                        best_serial_match = match

                # 如果序号匹配的文件中有汉字匹配度高的，直接返回
                if highest_serial_score > 0.5:  # 设置一个较高的阈值
                    print(f"序号+汉字最佳匹配: {best_serial_match} (分数: {highest_serial_score:.2f})")
                    return best_serial_match

                # 如果序号匹配但汉字匹配度不够高，记录最佳序号匹配，但继续全局汉字匹配
                print(f"序号匹配但汉字匹配度不足 (分数: {highest_serial_score:.2f})，继续全局匹配")

    # 第二步：全局纯汉字匹配（无论是否有序号匹配）
    best_global_match = None
    highest_global_score = 0

    for root_dir, _, files in os.walk(source_folder):
        for file in files:
            file_name, ext = os.path.splitext(file)
            if ext.lower() not in VALID_EXTENSIONS:
                continue

            # 清理文件名：去除数字和标点，只保留汉字
            cleaned_filename = clean_file_name(file_name)

            # 计算字符匹配比例
            char_match_ratio = calculate_char_match_ratio(report_chars, cleaned_filename)

            # 使用模糊匹配分数
            similarity = fuzz.partial_ratio(cleaned_report, cleaned_filename)

            # 检查核心词序列是否按顺序出现
            sequential_match = True
            last_index = -1
            for char in cleaned_report:
                current_index = cleaned_filename.find(char, last_index + 1)
                if current_index == -1:
                    sequential_match = False
                    break
                last_index = current_index

            # 综合评分
            total_score = char_match_ratio * 0.7 + similarity / 100 * 0.3
            if sequential_match:
                total_score += 0.2  # 顺序匹配加分

            # 调试信息
            debug_info = (
                f"全局匹配检测: '{report_name}' (序号: {serial_str}) -> '{file_name}'\n"
                f"清理后报表: '{cleaned_report}' (字符: {report_chars})\n"
                f"清理后文件: '{cleaned_filename}'\n"
                f"字符匹配率: {char_match_ratio:.2%}, 模糊匹配: {similarity}%, "
                f"顺序匹配: {sequential_match}, 总分: {total_score:.2f}"
            )
            print(debug_info)

            # 放宽字符匹配率阈值
            if char_match_ratio >= 0.8:  # 原为0.95
                print(f"字符匹配成功 (匹配率: {char_match_ratio:.2%})")
                return os.path.join(root_dir, file)

            # 放宽模糊匹配阈值
            if similarity >= 75:  # 原为85
                print(f"模糊匹配成功 (相似度: {similarity}%)")
                return os.path.join(root_dir, file)

            # 更新最佳匹配
            if total_score > highest_global_score:
                highest_global_score = total_score
                best_global_match = os.path.join(root_dir, file)

    # 降低全局匹配的阈值
    if highest_global_score > 0.4:  # 原为0.5
        print(f"全局最佳匹配: {best_global_match} (分数: {highest_global_score:.2f})")
        return best_global_match

    # 第三步：如果以上都没有匹配到，且有序号，则匹配只包含序号的文件（忽略汉字）
    if serial_str:
        print(f"尝试匹配只包含序号的文件: {serial_str}")
        for root_dir, _, files in os.walk(source_folder):
            for file in files:
                file_name, ext = os.path.splitext(file)
                if ext.lower() not in VALID_EXTENSIONS:
                    continue

                # 检查文件名是否只包含数字（可能是序号）
                if is_number_only_filename(file_name):
                    # 检查文件名中的数字是否与序号匹配
                    file_number = os.path.splitext(file)[0]
                    if file_number == serial_str:
                        print(f"找到只包含序号的文件: {file_name} (匹配序号: {serial_str})")
                        return os.path.join(root_dir, file)

                # 检查文件名是否包含序号（即使有其他字符）
                if serial_str in file_name:
                    # 进一步检查文件名中是否几乎没有汉字
                    cleaned_filename = clean_file_name(file_name)
                    if len(cleaned_filename) <= 2:  # 如果汉字很少，认为是序号文件
                        print(
                            f"找到以序号为主的文件: {file_name} (包含序号: {serial_str}, 汉字数量: {len(cleaned_filename)})")
                        return os.path.join(root_dir, file)

    # 没有找到匹配文件
    print(f"未匹配: '{report_name}' (序号: {serial_str}, 清理后: '{cleaned_report}')")
    return None


# 辅助函数：检查字符串是否包含汉字
def contains_chinese(text):
    """检查字符串是否包含汉字"""
    for char in text:
        if '\u4e00' <= char <= '\u9fff':
            return True
    return False


def load_mapping(excel_path, mapping_sheet="Sheet2"):
    """加载映射表，返回映射字典"""
    try:
        # 尝试读取映射表
        mapping_df = pd.read_excel(excel_path, sheet_name=mapping_sheet)

        # 检查必要的列
        if "原始区划" not in mapping_df.columns or "映射路径" not in mapping_df.columns:
            messagebox.showwarning("映射表格式错误",
                                   f"映射表 '{mapping_sheet}' 缺少必要的列('原始区划'或'映射路径')")
            return {}

        # 创建映射字典
        mapping_dict = {}
        for _, row in mapping_df.iterrows():
            original = str(row["原始区划"]).strip()
            mapped = str(row["映射路径"]).strip()
            if original and mapped:
                mapping_dict[original] = mapped
                print(f"映射: '{original}' -> '{mapped}'")

        return mapping_dict

    except Exception as e:
        messagebox.showinfo("映射表加载", f"未找到或无法加载映射表 '{mapping_sheet}': {str(e)}")
        return {}


def apply_mapping(source_path, mapping_dict):
    """应用映射到源路径"""
    # 尝试精确匹配
    if source_path in mapping_dict:
        return mapping_dict[source_path]

    # 尝试部分匹配（处理路径前缀）
    for original, mapped in mapping_dict.items():
        if source_path.startswith(original):
            # 替换路径前缀
            return source_path.replace(original, mapped, 1)

    # 没有匹配的映射，返回原路径
    return source_path


def show_unmatched_report(unmatched_reports):
    """显示未匹配到的报表名称"""
    if not unmatched_reports:
        return

    root = Tk()
    root.title("未匹配报表列表")
    root.geometry("600x400")

    Label(root, text="以下报表未找到匹配文件:", font=("Arial", 12, "bold")).pack(pady=10)

    # 创建文本框和滚动条
    text_frame = Frame(root)
    text_frame.pack(fill="both", expand=True, padx=10, pady=5)

    scrollbar = Scrollbar(text_frame)
    scrollbar.pack(side="right", fill="y")

    text_area = Text(text_frame, wrap="word", yscrollcommand=scrollbar.set)
    text_area.pack(fill="both", expand=True)
    scrollbar.config(command=text_area.yview)

    # 添加未匹配报表名称
    for report in unmatched_reports:
        text_area.insert("end", f"- {report}\n")

    text_area.config(state="disabled")

    Button(root, text="关闭", command=root.destroy).pack(pady=10)
    root.mainloop()


def main():
    # 1. 选择Excel文件
    excel_path = select_excel_file()
    if not excel_path:
        return

    # 2. 加载映射表（从Sheet2）
    mapping_dict = load_mapping(excel_path, mapping_sheet="Sheet2")

    # 3. 获取并选择sheet（排除映射表）
    all_sheets = get_sheets(excel_path)
    if not all_sheets:
        messagebox.showerror("错误", "Excel文件中没有找到任何sheet")
        return

    # 排除映射表sheet
    exclude_sheets = ["Sheet2"]  # 可以根据需要添加更多要排除的sheet
    selected_sheets = select_sheets(all_sheets, exclude=exclude_sheets)
    if not selected_sheets:
        return

    # 4. 选择目标文件夹
    target_folder = select_target_folder()
    if not target_folder:
        return

    # 5. 创建目标文件夹（如果不存在）
    os.makedirs(target_folder, exist_ok=True)

    # 6. 处理每个选中的sheet
    all_matched_files = []
    unmatched_reports = []  # 存储未匹配的报表名称

    for sheet_name in selected_sheets:
        try:
            df = pd.read_excel(excel_path, sheet_name=sheet_name)

            # 检查必要的列是否存在
            required_columns = ["上报区划", "报表名称", "原表序号", "总表序号"]
            missing_columns = [col for col in required_columns if col not in df.columns]

            if missing_columns:
                messagebox.showwarning("警告",
                                       f"Sheet '{sheet_name}' 缺少必要的列: {', '.join(missing_columns)}")
                continue

            # 处理每一行数据
            for index, row in df.iterrows():
                original_path = str(row["上报区划"]).strip()
                report_name = str(row["报表名称"]).strip()
                serial_number = row["原表序号"]  # 获取原表序号字段
                total_number = row["总表序号"]

                if not original_path or not report_name:
                    continue

                # 应用映射
                source_path = apply_mapping(original_path, mapping_dict)
                print(f"原始路径: {original_path} -> 映射后路径: {source_path}")

                # 检查源路径是否存在
                if not os.path.exists(source_path):
                    print(f"路径不存在: {source_path} (原始路径: {original_path})")
                    unmatched_reports.append(f"{report_name} (路径不存在: {source_path})")
                    continue

                # 查找匹配的文件（使用新的匹配逻辑）
                matched_file = find_first_file(source_path, report_name, serial_number)

                if matched_file:
                    all_matched_files.append(matched_file)

                    # 复制文件到目标文件夹
                    try:
                        # 获取原始文件名
                        original_filename = os.path.basename(matched_file)

                        # 确保总表序号不是NaN
                        if pd.isna(total_number):
                            base_name = original_filename
                        else:
                            # 添加总表序号前缀
                            base_name = f"{total_number}_{original_filename}"

                        # 构建目标路径
                        name, ext = os.path.splitext(base_name)
                        target_path = os.path.join(target_folder, base_name)

                        # 如果目标文件已存在，添加计数器
                        counter = 1
                        while os.path.exists(target_path):
                            target_name = f"{name}_{counter}{ext}"
                            target_path = os.path.join(target_folder, target_name)
                            counter += 1

                        shutil.copy2(matched_file, target_path)
                        print(f"已复制: {matched_file} -> {target_path}")

                    except Exception as e:
                        print(f"复制文件失败 {matched_file}: {str(e)}")
                else:
                    # 记录未匹配的报表名称
                    unmatched_reports.append(f"{report_name} (序号: {serial_number})")

        except Exception as e:
            messagebox.showerror("处理错误", f"处理sheet '{sheet_name}'时出错: {str(e)}")

    # 显示完成信息
    message = f"处理完成!\n\n共找到并复制了 {len(all_matched_files)} 个文件\n到目录: {target_folder}"

    if unmatched_reports:
        message += f"\n\n有 {len(unmatched_reports)} 个报表未找到匹配文件"
        # 显示未匹配报表窗口
        show_unmatched_report(unmatched_reports)

    messagebox.showinfo("完成", message)


if __name__ == "__main__":
    main()